"""
/** Copyright 2020 Zhejiang Lab and Zhejiang University. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================
*/
"""
import hashlib
import json
import os
from datetime import timedelta
from functools import partial
from urllib.parse import urljoin
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from utils import logRequest

# Create your views here.
from django.views import View
from my_models.models import Models, Share_Link, Share_Model
from my_datasets.models import Datasets
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework_jwt.utils import jwt_decode_handler
from django.http import JsonResponse, HttpResponse, Http404, FileResponse, HttpResponseForbidden
from django.core.files.storage import FileSystemStorage
from django.utils import timezone
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import parser_classes
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.parsers import FileUploadParser, MultiPartParser, JSONParser
import re
import uuid
from backend import settings
from user.models import User
import logging
from django.db.models import F

logger_name = 'my_datasets.views'
logger = logging.getLogger(logger_name)


class Upload(APIView):
    permission_classes = (IsAuthenticated,)

    @logRequest(logger_name)
    def post(self, request):
        my_dataset = Datasets()
        my_dataset.user = request.user
        file_info = request.data["file_info"]
        info = json.loads(file_info)
        my_dataset.file = request.data["file"]
        my_dataset.is_public = info["is_public"]
        my_dataset.dataset_name = info["dataset_name"]
        my_dataset.md5 = get_md5(my_dataset.file)
        # if Dataset.objects.filter(md5=my_dataset.md5) is not None:
        #     return Response(data="duplicate file", status=status.HTTP_400_BAD_REQUEST)
        if not my_dataset.file:
            return Response(data="no file for upload", status=status.HTTP_400_BAD_REQUEST)
        # (filename, extension) = os.path.splitext(my_dataset.dataset_name)
        # if extension not in['.pth', '.pkl']:
        #    return Response(data="wrong file for upload", status=status.HTTP_400_BAD_REQUEST)
        try:
            my_dataset.save()
            url = urljoin('file/', my_dataset.file.name)
            my_dataset.url = url
            my_dataset.save()
        except Exception as e:
            return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
        return Response(data="success upload", status=status.HTTP_200_OK)

    @logRequest(logger_name)
    def get(self, request):
        user_info = request.user
        dataset = Datasets.objects.filter(user=user_info).values(
            "id", "dataset_name", "is_public", "url", "created_time"
        )
        share_dataset = Share_Model.objects.filter(user=user_info).filter(file_type='d').values("file_id")
        share_dataset_list = list(share_dataset)
        file_id_list = []
        for v in share_dataset_list:
            file_id_list.append(v["file_id"])
        dataset_share = Datasets.objects.filter(id__in=file_id_list).values(
                "id", "dataset_name", "is_public", "url", "created_time"
                )
        dataset_share_list = list(dataset_share)
        dataset_list = list(dataset)
        for v in dataset_list:
            v["is_possessed"] = True
        for v in dataset_share_list:
            v["is_possessed"] = False
        dataset_list.extend(dataset_share_list)
        return Response(dataset_list, status=status.HTTP_200_OK)

    def delete(self, request):
       dataset_ids = [int(v) for v in request.query_params.getlist('dataset_ids[]', [])]
       try:
           Datasets.objects.filter(id__in=dataset_ids).filter(user=request.user).delete()
           return Response(data="success", status=status.HTTP_200_OK)
       except:
           return Response(data="error", status=status.HTTP_400_BAD_REQUEST)

    @logRequest(logger_name)
    def put(self, request):
        user = request.user
        file_info = request.data["file_info"]
        info = json.loads(file_info)
        dataset_id = info["dataset_id"]
        my_dataset = Datasets.objects.filter(id=dataset_id).first()
        if my_dataset.user != user:
            return Response(data="wrong user", status=status.HTTP_400_BAD_REQUEST)
        my_dataset.is_public = info["is_public"]
        my_dataset.dataset_name = info["dataset_name"]
        try:
            my_dataset.save()
        except Exception as e:
            return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
        return Response(data="success", status=status.HTTP_200_OK)


class PublicDatasets(APIView):
    @logRequest(logger_name)
    def get(self, request):
        try:
            datasets = Datasets.objects.filter(is_public=True).values("id", "dataset_name", "url", "created_time", username=F("user__username"))
        except Exception as e:
            return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
        logger.debug(datasets)
        return Response(datasets, status=status.HTTP_200_OK)


class ShareLink(APIView):
    permission_classes = (IsAuthenticated,)

    @logRequest(logger_name)
    def post(self, request):
        link = Share_Link()
        link.file_id = request.data["file_id"]
        dataset = Datasets.objects.filter(id=link.file_id).filter(user=request.user)
        if len(dataset) == 0:
            return Response(data='No such file', status=status.HTTP_400_BAD_REQUEST)
        link.file_type = request.data["file_type"]
        duration = request.data["duration"]
        link.expired_time = timezone.now() + timedelta(days=int(duration))
        fn = uuid.uuid1().hex
        link.url_str = fn
        link.save()
        return Response(data=fn, status=status.HTTP_200_OK)


class ShareDataset(APIView):
    permission_classes = (IsAuthenticated,)

    @logRequest(logger_name)
    def post(self, request):
        url_str = request.data["share_link"]
        link = Share_Link.objects.filter(url_str=url_str, file_type="d").first()
        if link is None:
            return Response(data="invalid link", status=status.HTTP_400_BAD_REQUEST)
        time_now = timezone.now()
        if time_now > link.expired_time:
            return Response(data="over time", status=status.HTTP_400_BAD_REQUEST)
        share_dataset = Share_Model.objects.filter(file_id=link.file_id).filter(file_type=link.file_type).filter(
            user=request.user)
        if len(share_dataset) > 0:
            return Response(data="already exist", status=status.HTTP_400_BAD_REQUEST)
        dataset = Datasets.objects.filter(id=link.file_id).first()
        if (dataset.user == request.user):
            return Response(data="You are the owner of dataset", status=status.HTTP_400_BAD_REQUEST)
        _share_dataset = Share_Model()
        _share_dataset.file_id = link.file_id
        _share_dataset.file_type = link.file_type
        _share_dataset.user = request.user
        _share_dataset.expired_time = time_now + timedelta(days=7)
        _share_dataset.save()
        return Response(data="obtain permission", status=status.HTTP_200_OK)


def get_md5(file, block_size=65536):
    md5 = hashlib.md5()
    for buf in iter(partial(file.read, block_size), b''):
        md5.update(buf)
    return md5.hexdigest()